/****************************************
 ****************************************
 **   This document written by CTonk.  **
 **         ctonk@hotmail.com          **
 ****************************************
 ****************************************/

// encryption.cpp

#ifndef H_ENCRYPTION
#define H_ENCRYPTION

#include< iostream >
#include< fstream >
#include< math.h >
#include< time.h >
#include< Windows.h >
using namespace std;

void encrypt_str( char* );
void decode_str( char* );
void encrypt( char* );
void decode( char* );

namespace TONKS_CRYPT
{
	char* TEMP = "tonks_temp_file.txt";
	char block, sub_block, ch;
	int ctr = 0, ctr2 = 0;
	_int64 inval = 0;
	void encrypt_str( char*, char* );
	void decode_str( char*, char* );
	void encrypt_file( char*, char* );
	void decode_file( char*, char* );
	void open_error( ifstream&, char*, bool );
	int Rand( int, int );
}

//int main() { // I keep this here for easier testing
//
//	return 0;
//}

void TONKS_CRYPT::open_error( ifstream& fin, char* file, bool quit )
{
	fin.close();
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 12 );
	cout << "Error opening " << file << endl;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 7 );
	if ( quit )
		exit( 0 );
	return;
}

int TONKS_CRYPT::Rand( int a, int b )
{
	return ( (rand() % b) + a );
}

void encrypt(char* file)
{
	TONKS_CRYPT::encrypt_file( file, TONKS_CRYPT::TEMP );
	TONKS_CRYPT::encrypt_file( TONKS_CRYPT::TEMP, file );
	remove( TONKS_CRYPT::TEMP );
	return;
}

void decode( char* file )
{
	TONKS_CRYPT::decode_file( file, TONKS_CRYPT::TEMP );
	TONKS_CRYPT::decode_file( TONKS_CRYPT::TEMP, file );
	remove( TONKS_CRYPT::TEMP );
	return;
}

void TONKS_CRYPT::encrypt_file(char* file_in, char* file_out)
{
	ifstream fin( file_in );
	if ( !fin )
		open_error( fin, file_in, 1 );

	ofstream fout( file_out );

	//Keeps looping until EOF
	ctr2 = 0;
	while ((ch = fin.get()) != EOF)
	{
		inval = (_int64)ch;

		//Randomizer to choose which function from
		//which block to use
		block = Rand(1,6);
		sub_block = Rand(1,6);

		//This whole mess of shizzle contains the char to int functions,
		//obviously needed because the calling order is random; seeded
		//with the user-defined variable 'seed'
		if (block == 1)
		{
			fout << "A";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = 19*(inval) + 551;
				break;
			case 2:
				fout << "B";
				inval = 28*(inval) + 47;
				break;
			case 3:
				fout << "C";
				inval = 4*(inval)*(inval) + 213;
				break;
			case 4:
				fout << "D";
				inval = 8*(inval)*(inval) + 4;
				break;
			case 5:
				fout << "E";
				inval = 17*(inval)*(inval) + 1123;
				break;
			case 6:
				fout << "F";
				inval = 50*(inval) - 50;
				break;
			default:
				break;
			}
		}
		if (block == 2)
		{
			fout << "B";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = 34*(inval) - 33;
				break;
			case 2:
				fout << "B";
				inval = 90*(inval) - 21;
				break;
			case 3:
				fout << "C";
				inval = 4*(inval)*(inval) - 65489;
				break;
			case 4:
				fout << "D";
				inval = 213*(inval)*(inval) - 654;
				break;
			case 5:
				fout << "E";
				inval = 16*(inval) - 92;
				break;
			case 6:
				fout << "F";
				inval = 19*(inval) - 1;
				break;
			default:
				break;
			}
		}
		if (block == 3)
		{
			fout << "C";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = 81*(inval)*(inval) + 549;
				break;
			case 2:
				fout << "B";
				inval = 321*(inval) - 65412;
				break;
			case 3:
				fout << "C";
				inval = 16*(inval)*(inval)*(inval)*(inval);
				break;
			case 4:
				fout << "D";
				inval = 64*(inval)*(inval) - 8;
				break;
			case 5:
				fout << "E";
				inval = 20*(inval) - 9874;
				break;
			case 6:
				fout << "F";
				inval = 460*(inval) - 551;
				break;
			default:
				break;
			}
		}
		if (block == 4)
		{
			fout << "D";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = -56*(inval) + 92;
				break;
			case 2:
				fout << "B";
				inval = 9*(inval)*(inval)*(inval)*(inval) -981;
				break;
			case 3:
				fout << "C";
				inval = 23*(inval)*(inval) + 951;
				break;
			case 4:
				fout << "D";
				inval = 140*(inval)*(inval) + 648;
				break;
			case 5:
				fout << "E";
				inval = 852*(inval) + 1;
				break;
			case 6:
				fout << "F";
				inval = 111*(inval) + 351;
				break;
			default:
				break;
			}
		}
		if (block == 5)
		{
			fout << "E";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = 19*(inval)*(inval) - 5;
				break;
			case 2:
				fout << "B";
				inval = 109*(inval) - 109;
				break;
			case 3:
				fout << "C";
				inval = 45*(inval) + 2777;
				break;
			case 4:
				fout << "D";
				inval = 874*(inval)*(inval) -4;
				break;
			case 5:
				fout << "E";
				inval = 7*(inval) + 947;
				break;
			case 6:
				fout << "F";
				inval = 8*(inval) + 95;
				break;
			default:
				break;
			}
		}
		if (block == 6)
		{
			fout << "F";
			switch (sub_block)
			{
			case 1:
				fout << "A";
				inval = 21*(inval) + 488;
				break;
			case 2:
				fout << "B";
				inval = 92*(inval) + 84;
				break;
			case 3:
				fout << "C";
				inval = 452*(inval)*(inval) - 9874;
				break;
			case 4:
				fout << "D";
				inval = 936*(inval)*(inval) - 8465;
				break;
			case 5:
				fout << "E";
				inval = 871*(inval) + 871;
				break;
			case 6:
				fout << "F";
				inval = 947*(inval) + 10000000;
				break;
			default:
				break;
			}
		}

		fout << inval;

		//So there's not one huge-normous line of code...		
		ctr2++;
		if ( ctr2 %7 == 0 )
			fout << '\n';
	
	}
	//Insert EOF character
	fout << '~';

	fin.close();
	fout.close();

	return;
}

void TONKS_CRYPT::decode_file( char* file_in, char* file_out )
{
	ifstream fin( file_in );
	if ( !fin )
		open_error( fin, file_in, 1) ;

	ofstream fout( file_out );

	while (1)
	{
		fin >> block;
		if (block == '~')
		{
			fin.close();
			fout.close();
			return;
		}	
		fin >> sub_block;
		fin >> inval;
		//This plethora of crap is for the int to char conversions,
		//using the block and sub_block as routers to get the
		//right functions... 'cause it's all random shizzle baby :)
		if (block == 'A')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)(((inval)-551)/19);
				break;
			case 'B':
				ch = (char)(((inval)-47)/28);
				break;
			case 'C':
				//Uses built-in power funcion to take the
				//square-root and fourth-root of inval
				//when needed.
				ch = (char)pow((double)(((inval)-213)/4),.5);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)-4)/8),.5);
				break;
			case 'E':
				ch = (char)pow((double)(((inval)-1123)/17),.5);
				break;
			case 'F':
				ch = (char)(((inval)+50)/50);
				break;
			default:
				break;
			}
		}
		if (block == 'B')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)(((inval)+33)/34);
				break;
			case 'B':
				ch = (char)(((inval)+21)/90);
				break;
			case 'C':
				ch = (char)pow((double)(((inval)+65489)/4),.5);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)+654)/213),.5);
				break;
			case 'E':
				ch = (char)(((inval)+92)/16);
				break;
			case 'F':
				ch = (char)(((inval)+1)/19);
				break;
			default:
				break;
			}
		}
		if (block == 'C')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)pow((double)(((inval)-549)/81),.5);
				break;
			case 'B':
				ch = (char)(((inval)+65412)/321);
				break;
			case 'C':
				ch = (char)pow((double)(((inval))/16),.25);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)+8)/64),.5);
				break;
			case 'E':
				ch = (char)(((inval)+9874)/20);
				break;
			case 'F':
				ch = (char)(((inval)+551)/460);
				break;
			default:
				break;
			}
		}
		if (block == 'D')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)(((inval)-92)/-56);
				break;
			case 'B':
				ch = (char)pow((double)(((inval)+981)/9),.25);
				break;
			case 'C':
				ch = (char)pow((double)(((inval)-951)/23),.5);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)-648)/140),.5);
				break;
			case 'E':
				ch = (char)(((inval)-1)/852);
				break;
			case 'F':
				ch = (char)(((inval)-351)/111);
				break;
			default:
				break;
			}
		}
		if (block == 'E')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)pow((double)(((inval)+5)/19),.5);
				break;
			case 'B':
				ch = (char)(((inval)+109)/109);
				break;
			case 'C':
				ch = (char)(((inval)-2777)/45);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)+4)/874),.5);
				break;
			case 'E':
				ch = (char)(((inval)-947)/7);
				break;
			case 'F':
				ch = (char)(((inval)-95)/8);
				break;
			default:
				break;
			}
		}
		if (block == 'F')
		{
			switch (sub_block)
			{
			case 'A':
				ch = (char)(((inval)-488)/21);
				break;
			case 'B':
				ch = (char)(((inval)-84)/92);
				break;
			case 'C':
				ch = (char)pow((double)(((inval)+9874)/452),.5);
				break;
			case 'D':
				ch = (char)pow((double)(((inval)+8465)/936),.5);
				break;
			case 'E':
				ch = (char)(((inval)-871)/871);
				break;
			case 'F':
				ch = (char)(((inval)-10000000)/947);
				break;
			default:
				break;
			}
		}
		//Spits out our nice pretty decoded character,
		fout << ch;
	}
	fin.close();
	fout.close();
	return;
}

#endif